home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / libs / viewwrld / viewwrld.lha / viewworld / lgd / lgd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-21  |  39.7 KB  |  1,436 lines

  1. /* $Id: lgd.c,v 1.7 89/09/20 17:49:12 mbp Exp $
  2.  *
  3.  * lgd.c: top-level LGD procedures
  4.  */
  5.  
  6. /************************************************************************
  7.  *        Copyright (C) 1989 by Mark B. Phillips                  *
  8.  *                                     *
  9.  * Permission to use, copy, modify, and distribute this software and    *
  10.  * its documentation for any purpose and without fee is hereby granted, *
  11.  * provided that the above copyright notice appear in all copies and    *
  12.  * that both that copyright notice and this permission notice appear in *
  13.  * supporting documentation, and that the name of Mark B. Phillips or   *
  14.  * the University of Maryland not be used in advertising or publicity   *
  15.  * pertaining to distribution of the software without specific, written *
  16.  * prior permission.  This software is provided "as is" without express *
  17.  * or implied warranty.                                                 *
  18.  ************************************************************************/
  19.  
  20. #include    <stdio.h>
  21. #include    "lgd.h"
  22. #include    "internal.h"
  23. #include    "mf.h"
  24. #include    "vector.h"
  25. #include    "dpu.h"
  26.  
  27. /************************************************************************
  28.  *              PUBLIC DEFINITIONS                *
  29.  ************************************************************************/
  30.  
  31. /* Current dimension (always 3 for now): */
  32. int    lgd_dim=3;
  33.  
  34. /* Length of segment headers: */
  35. int    lgd_header_length=4;
  36.  
  37. /* Length of segment trailers: */
  38. int    lgd_trailer_length=1;    
  39.  
  40. /* Error message: */
  41. char    *lgd_error=NULL;
  42.  
  43. /* Format number for world files: */
  44. int    lgd_world_file_fmt=3;
  45.  
  46. /*
  47.  * World file format history:
  48.  *  1. The original version.
  49.  * 2. Changed "lgd_save/lgd_load" to write out current segment number
  50.  *     instead of stack of current segments (segment nesting
  51.  *     eliminated).  Also changed dpu.c to write out lgd_View3
  52.  *     structure instead of separate eye, focus, etc.
  53.  * 3. Exactly the same as 2, but uses new lgd_View3 structure, which
  54.  *     has h1 and h2 fields now.
  55.  */
  56.  
  57. /* Tolerance, as fraction of screen width, for picking */
  58. #define PICK_TOLERANCE_DEFAULT 0.01
  59. double    lgd_pick_tolerance = PICK_TOLERANCE_DEFAULT;
  60.  
  61. /* Corners of world box (lgd_wbox[0]=low vals, lgd_wbox[1]=high vals): */
  62. double    lgd_wbox[2][MAXDIM];
  63.  
  64. /* Scaling factors used  to convert to canonincal integer coords: */
  65. double    lgd_wscale[MAXDIM];
  66.  
  67. /*----------------------End of Public Definitions-----------------------*/
  68.  
  69. /************************************************************************
  70.  *             PRIVATE DEFINITIONS                *
  71.  ************************************************************************/
  72.  
  73. #define        YES        1
  74. #define        NO        0
  75.  
  76. static int    pen_status;
  77. #define        UP        0
  78. #define        DOWN        1
  79. #define        PEN_IS_UP    (!pen_status)
  80. #define        PEN_IS_DOWN    (pen_status)
  81.  
  82. /* Current (legal) Point (takes clipping into account): */
  83. static double    cp[MAXDIM];
  84.  
  85. /* Current Real Point (does not take clipping into account): */
  86. static double   crp[MAXDIM];
  87.  
  88. /* Number ("name") for "no" segment: */
  89. #define NULL_SEGMENT ((mfe)0)
  90.  
  91. /* Number of currently open segment: */
  92. static mfe cur_segment=NULL_SEGMENT;
  93.  
  94. /* Tell whether there is a segment open: */
  95. #define        SEGMENT_OPEN    (cur_segment!=NULL_SEGMENT)
  96. #define        NO_SEGMENT_OPEN    (cur_segment==NULL_SEGMENT)
  97.  
  98. /* Current drawing color and style: */
  99. static mfe    cur_color;
  100. static mfe    cur_style;
  101.  
  102. /* Visibility flags: */
  103. #define        VISIBLE            1
  104. #define        INVISIBLE        0
  105.  
  106. /* Internal functions: */
  107. static mfa    segment_address();
  108. static mfe    generate_unique_segment_number();
  109. static char *error_string();
  110.  
  111. /* Error handling things: */
  112. static char *lgd_internal_error;
  113. #define MAKE_LGD_ERR(s,e) {lgd_error = error_string(s,e);e=NULL;}
  114. #define MAKE_LGD_INTERNAL_ERR(s,e) \
  115.      {lgd_internal_error = error_string(s,e);e=NULL;}
  116.  
  117. /*------------------End of Private Definitions--------------------------*/
  118.  
  119. /************************************************************************
  120.  *              PUBLIC PROCEDURES                *
  121.  ************************************************************************/
  122.  
  123. /*-----------------------------------------------------------------------
  124.  * Function:     lgd_initialize
  125.  * Description:  initialize LGD
  126.  * Arguments:    (none)
  127.  * Returns:      nothing
  128.  * Notes:        This procedure must be called before any other
  129.  *               LGD procedures.
  130.  */
  131. lgd_initialize()
  132. {
  133.   mf_initialize();        /*  Initialize the metafile */
  134.   if (mf_error!=NULL) {
  135.     MAKE_LGD_ERR("(MetaFile) ",mf_error);
  136.     return;
  137.   }
  138.   dpu_initialize();        /*  Initialize the dpu  */
  139.   if (dpu_error!=NULL) {
  140.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  141.     return;
  142.   }
  143.   pen_status = UP;        /*  Pen is initially UP */
  144.   cur_color = LGD_WHITE;    /*  Color defaults to white */
  145.   cur_style = 1;        /*  Line style defaults to 1 */
  146. }
  147.  
  148. /*-----------------------------------------------------------------------
  149.  * Function:     lgd_define_world
  150.  * Description:  defines the world coordinate system
  151.  * Arguments IN: dimension: the dimension of the world
  152.  *               wbox_low: low corner of world
  153.  *               wbox_high: high corner of world
  154.  * Returns:      nothing
  155.  */
  156. lgd_define_world( dimension, wbox_low, wbox_high )
  157. int dimension;
  158. double wbox_low[], wbox_high[];
  159. {
  160.   int i;
  161.   lgd_View3 view;
  162.                 /* check validity of dimension */
  163.   if (dimension != 3) {
  164.     lgd_error = E_bad_dim;
  165.     return;
  166.   }
  167.   lgd_dim = dimension;        /* Set global dim variable    */
  168.   for (i=0; i<lgd_dim; ++i) {
  169.                 /* check validity of coords */
  170.     if (wbox_low[i]>wbox_high[i]) {
  171.       lgd_error = E_bad_wld_bdy;
  172.       return;
  173.     }
  174.     lgd_wbox[0][i] = wbox_low[i];    /* Set world            */
  175.     lgd_wbox[1][i] = wbox_high[i];    /* coordinate values    */
  176.   }
  177.   for (i=0; i<lgd_dim; ++i)    /* Set scale factors    */
  178.     lgd_wscale[i] =    ( (double) MF_max_val ) 
  179.       / (lgd_wbox[1][i]-lgd_wbox[0][i]);
  180.   LGD_copy_vec( cp, lgd_wbox[0] );    /* Set default current  */
  181.   LGD_copy_vec( crp, lgd_wbox[0] );    /* points = lower corner */
  182.   dpu_get_default_view( &view );
  183.   dpu_set_view( &view );
  184. }
  185.  
  186. /*-----------------------------------------------------------------------
  187.  * Function:     lgd_delete_all
  188.  * Description:  Delete the current picture completely
  189.  * Arguments:    (none)
  190.  * Returns:      nothing
  191.  * Notes:        This clears out the current picture, leaving the
  192.  *               current world definition and menu setting intact.
  193.  *
  194.  *               NOTE: Right now I can't see that this proc should do
  195.  *               anything other than exactly what lgd_intialize does.
  196.  *               I'm making it a separate proc because it performs a
  197.  *               conceptually different task, though, and because at
  198.  *               some point in the future it and lgd_initialize may
  199.  *               need to perform different tasks.
  200.  */
  201. lgd_delete_all()
  202. {
  203.   lgd_initialize();
  204. }
  205.  
  206. /*-----------------------------------------------------------------------
  207.  * Function:     lgd_inquire_world
  208.  * Description:  Get the current world definition data
  209.  * Arguments OUT: *dimension: the dimension of the world
  210.  *               wbox_low: lower corner of world
  211.  *               wbox_high: upper corner of world
  212.  * Returns:      nothing
  213.  */
  214. lgd_inquire_world( dimension, wbox_low, wbox_high )
  215. int *dimension;
  216. double wbox_low[],wbox_high[];
  217. {
  218.   *dimension = lgd_dim;
  219.   if (lgd_dim!=0) {
  220.     LGD_copy_vec( wbox_low,  lgd_wbox[0] );
  221.     LGD_copy_vec( wbox_high, lgd_wbox[1] );
  222.   }
  223. }
  224.  
  225. /*-----------------------------------------------------------------------
  226.  * Function:     lgd_move_abs
  227.  * Description:  Move the current point to a new point
  228.  * Arguments IN: v: the point to move to
  229.  * Returns:      nothing
  230.  * Notes:        This procedure does clipping
  231.  */
  232. lgd_move_abs( v )
  233.      double v[];
  234. {
  235.    if (in_world_box(v)) move_abs(v);
  236.    LGD_copy_vec( crp, v );
  237. }
  238.  
  239. /*-----------------------------------------------------------------------
  240.  * Function:     lgd_move_rel
  241.  * Description:  Move the current point by relative displacement
  242.  * Arguments IN: dv: the vector to add to current point
  243.  * Returns:      nothing
  244.  * Notes:        cp+dv MUST be inside (or on the boundary of) the world.
  245.  *               If it is not, an error is set and the current point
  246.  *               is left unchanged.
  247.  */
  248. lgd_move_rel( dv )
  249.      double dv[];
  250. {
  251.   double v[MAXDIM];
  252.   
  253.   LGD_add_vec( v, crp, dv );
  254.   lgd_move_abs( v );
  255. }
  256.  
  257. /*--------------------------------------------------------------
  258.  * Function:     lgd_draw_abs
  259.  * Description:  Draw from the current point to a new point, and
  260.  *               then make that new point the current point
  261.  * Arguments IN: v: the point to draw to
  262.  * Returns:      nothing
  263.  * Notes:        This procedures does clipping
  264.  */
  265. lgd_draw_abs( v )
  266.      double v[];
  267. {
  268.   double p[MAXDIM];
  269.   int clip1, visible;
  270.  
  271.   LGD_copy_vec(p, v);
  272.   clipit(crp, p, &clip1, &visible);
  273.   if (visible) {
  274.     if (clip1) move_abs(crp);
  275.     draw_abs(p);
  276.   }
  277.   LGD_copy_vec(crp, v);
  278. }
  279.  
  280. /*-----------------------------------------------------------------------
  281.  * Function:     lgd_draw_rel
  282.  * Description:  Draw a line from current point to current point
  283.  *               plus displacement vector, leaving current point
  284.  *               at the final endpont of the line drawn.
  285.  * Arguments IN: dv: the vector to add to current point
  286.  * Returns:      nothing
  287.  * Notes:        cp+dv MUST be inside (or on the boundary of) the world.
  288.  *               If it is not, an error is set and the current point
  289.  *               is left unchanged.
  290.  */
  291. lgd_draw_rel( dv )
  292.      double dv[];
  293. {
  294.   double v[MAXDIM];
  295.   
  296.   LGD_add_vec( v, crp, dv );
  297.   lgd_draw_abs( v );
  298. }
  299.  
  300. /*-----------------------------------------------------------------------
  301.  * Function:     lgd_point
  302.  * Description:  Draw a point at the current point
  303.  * Arguments:    (none)
  304.  * Returns:      nothing
  305.  * Notes:        This only really draws a point if the current real
  306.  *               point is inside the world box.  Otherwise, it does
  307.  *               nothing (the point is clipped).
  308.  */
  309. lgd_point()
  310. {
  311.   if NO_SEGMENT_OPEN {
  312.     lgd_error = E_pt_noseg;
  313.     return;
  314.   }
  315.   if (in_world_box(crp)) {
  316.     mf_append( MF_point );
  317.     if (mf_error==NULL)
  318.       dpu_point();
  319.     else
  320.       MAKE_LGD_ERR("(MetaFile) ",mf_error);
  321.   }
  322. }
  323.  
  324. /*-----------------------------------------------------------------------
  325.  * Function:     lgd_update_display
  326.  * Description:  Make sure the display is up to date
  327.  * Arguments:    (none)
  328.  * Returns:      nothing
  329.  */
  330. lgd_update_display()
  331. {
  332.   dpu_update_display();
  333.   if (dpu_error!=NULL)
  334.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  335. }
  336.  
  337. /*-----------------------------------------------------------------------
  338.  * Function:     lgd_begin_segment
  339.  * Description:  begin a new segment
  340.  * Arguments OUT: *segment_number: the number of the new segment
  341.  * Returns:      nothing
  342.  * Notes:        Segment numbers are assigned automatically
  343.  */
  344. lgd_begin_segment( segment_number )
  345.      int *segment_number;
  346. {
  347.   mfa save;
  348.   mfe ivec[MAXDIM];
  349.  
  350.   if (SEGMENT_OPEN) {        /* make sure there is no  */
  351.     lgd_error = E_seg_open;    /* segment already open */
  352.     return;
  353.   }                /* get number for new segment */
  354.   cur_segment = 
  355.     (mfe)(*segment_number = generate_unique_segment_number());
  356.   if (lgd_internal_error!=NULL) {
  357.     MAKE_LGD_ERR("",lgd_internal_error);
  358.     return;
  359.   }
  360.   save = mf_last_addr();        /* Save current end of MF */
  361.   mf_append( MF_begin_segment );     /* BEGINNING OF HEADER */
  362.   mf_append( cur_segment );     /* segment number  */
  363.   mf_append( (mfe)VISIBLE );    /* visibility          */
  364.   mf_append( (mfe) 0 );            /* length; will be set when */
  365.                 /* segment is closed)  */
  366.                     /* END OF HEADER       */
  367.   /* 
  368.    * IMPORTANT NOTE: If the length of (number of words contained in)
  369.    * the header is changed, the setting of the external variable
  370.    * lgd_header_length (at the top of this file) should be changed
  371.    * appropriately.
  372.    */
  373.  
  374.   mf_append( MF_line_style ); /*  Establish current line style */
  375.   mf_append( cur_style );
  376.   mf_append( MF_color );    /*  Establish current color */
  377.   mf_append( cur_color );
  378.   mf_append( MF_pen_up );    /* Move to current point */
  379.   can_int_coord( ivec, cp );    
  380.   mf_append_array( ivec, lgd_dim );
  381.   if PEN_IS_DOWN        /* Restore current pen status  */
  382.     mf_append( MF_pen_down );
  383.   /* If any error has been encountered, restore the MF to the way it
  384.    *  was upon entry. */
  385.   if (mf_error) {
  386.     mf_truncate( save );
  387.     cur_segment = NULL_SEGMENT;
  388.     MAKE_LGD_ERR("(MetaFile) ", mf_error);
  389.   }
  390.   else {
  391.     dpu_begin_segment( cur_segment );
  392.     if (dpu_error!=NULL)
  393.       MAKE_LGD_ERR("(DPU) ",dpu_error);
  394.   }
  395. }
  396.  
  397. /*-----------------------------------------------------------------------
  398.  * Function:     lgd_end_segment
  399.  * Description:  Ends the current segment
  400.  * Arguments:    (none)
  401.  * Returns:      nothing
  402.  * Notes:        Does nothing if there is no segment currently
  403.  *               open.
  404.  */
  405. lgd_end_segment()
  406. {
  407.   mfa seg_addr, seg_length;
  408.  
  409.   if (NO_SEGMENT_OPEN) {    /*  Make sure there is a seg open */
  410.     lgd_error = E_cs_noseg;
  411.     return;
  412.   }
  413.   mf_append( MF_end_segment );    /* BEGINNING OF TRAILER    */
  414.                 /* END OF TRAILER    */
  415.   /* 
  416.    * IMPORTANT NOTE: If the length of (number of words contained in)
  417.    * the trailer is changed, the setting of the external variable
  418.    * lgd_trailer_length (at the top of this file) should be changed
  419.    * appropriately.
  420.    */
  421.   if (mf_error) {
  422.     MAKE_LGD_ERR("(MetaFile) ",mf_error);
  423.     return;
  424.   }
  425.   /* Now compute the length of the segment just closed and put it in
  426.    * the header */
  427.   seg_addr = segment_address( cur_segment );
  428.   seg_length = mf_last_addr() - seg_addr + 1;
  429.   if (seg_length > MAX_MFE_VAL) {
  430.     lgd_error = E_seg_too_long;
  431.     return;
  432.   }
  433.   mf_poke( (mfa)(seg_addr+LEN_OS), (mfe)seg_length );
  434.   cur_segment = NULL_SEGMENT;
  435.   dpu_end_segment();
  436.   if (dpu_error!=NULL)
  437.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  438. }
  439.  
  440. /*-----------------------------------------------------------------------
  441.  * Function:     lgd_delete_segment
  442.  * Description:  Delete a segment
  443.  * Arguments IN: segment_number: number of segment to delete
  444.  * Returns:      nothing
  445.  * Notes:        Deleting the currently open segment is not
  446.  *               allowed.  An attempt to do so causes an error.
  447.  */
  448. lgd_delete_segment( segment_number )
  449. int segment_number;
  450. {
  451.   mfa first, last;
  452.  
  453.     /* First make sure it's not the current segment */
  454.   if ((mfe)segment_number==cur_segment) {
  455.     lgd_error = E_del_open_seg;
  456.     return;
  457.   }
  458.     /* Then find its address in the MF */
  459.   first = segment_address( (mfe)(segment_number) );
  460.   if (first==NULL_SEG_ADDRESS) {
  461.     lgd_error = E_del_non_seg;
  462.     return;
  463.   }
  464.     /* Tell the DPU to erase it */
  465.   dpu_delete_segment( (mfe)(segment_number) );
  466.   if (dpu_error!=NULL) {
  467.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  468.     return;
  469.   }
  470.     /* Find its end and take it out */
  471.   last = first + mf_peek(first+LEN_OS) - 1;
  472.   mf_compress( first, last );
  473.   if (mf_error) {
  474.     MAKE_LGD_ERR("(MetaFile) ",mf_error);
  475.   }
  476.  
  477. }
  478.  
  479. /*-----------------------------------------------------------------------
  480.  * Function:     lgd_set_segment_visibility
  481.  * Description:  Set the visibility of a segment
  482.  * Arguments IN: segment_number: number of segment to be set
  483.  *               visibility_status: nonzero means set to visible;
  484.  *                 zero means set to invisible
  485.  * Returns:      nothing
  486.  */
  487. lgd_set_segment_visibility( segment_number, visibility_status )
  488.      int segment_number, visibility_status;
  489. {
  490.   mfa address;
  491.  
  492.     /* Find the segment */  
  493.   address = segment_address( (mfe)segment_number );
  494.   if (address==NULL_SEG_ADDRESS) {
  495.     lgd_error = E_visi_noseg;
  496.     return;
  497.   }
  498.     /* Change its visibility attribute in the MF */
  499.   visibility_status = (visibility_status==0) ? INVISIBLE : VISIBLE;
  500.   mf_poke( (mfa)(address+VIS_OS), (mfe)visibility_status );
  501.     /* Tell the DPU to change the attribute too */
  502.   dpu_set_segment_visibility( (mfe)segment_number, visibility_status );
  503.   if (dpu_error!=NULL)
  504.     MAKE_LGD_ERR("(DPU )",dpu_error);
  505.   return;
  506. }
  507.  
  508. /*-----------------------------------------------------------------------
  509.  * Function:     lgd_save_world
  510.  * Description:  Save the current world in a file
  511.  * Arguments IN: fname: name of file to write to
  512.  * Returns:      nothing
  513.  */
  514. lgd_save_world( fname )
  515.      char *fname;
  516. {
  517.   FILE *fp;
  518.   int items_written;
  519.   
  520.   fp = fopen( fname, "w" );
  521.   if (fp==NULL) {
  522.     lgd_error = E_sw_bad_fname;
  523.     return;
  524.   }
  525.   /*        Write the format number:            */
  526.   items_written = fwrite( (char*)&lgd_world_file_fmt,
  527.                    sizeof(int), 1, fp );
  528.   if (items_written!=1) {
  529.     lgd_error = E_sw_bad_write;
  530.     goto closeit;
  531.   }
  532.   
  533.   lgd_save( fp ); 
  534.   if (lgd_internal_error) {
  535.     MAKE_LGD_ERR("",lgd_internal_error);
  536.     goto closeit;
  537.   }
  538.   mf_save( fp );
  539.   if (mf_error) {
  540.     MAKE_LGD_ERR("(MetaFile) ",mf_error);
  541.     goto closeit;
  542.   }
  543.   dpu_save( fp );
  544.   if (dpu_error) {
  545.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  546.     goto closeit;
  547.   }
  548.  closeit:
  549.   fclose(fp);
  550. }
  551.  
  552. /*-----------------------------------------------------------------------
  553.  * Function:     lgd_load_world
  554.  * Description:  load a new world from a file
  555.  * Arguments IN: fname: name of file to read from
  556.  * Returns:      nothing
  557.  * Notes:        deletes the current world and all current settings
  558.  *               before loading new world
  559.  */
  560. lgd_load_world( fname )
  561.      char *fname;
  562. {
  563.   FILE *fp;
  564.   int items_read, format;
  565.   
  566.   fp = fopen( fname, "r" );
  567.   if (fp==NULL) {
  568.     lgd_error = E_lw_bad_fname;
  569.     return;
  570.   }
  571.   
  572.   /*        Read the format number:                */
  573.   items_read = fread( (char*)&format,
  574.                sizeof(int), 1, fp );
  575.   if (items_read!=1) {
  576.     lgd_error = E_lw_bad_read;
  577.     goto closeit;
  578.   }
  579.   /*        Make sure it agrees with the current format    */
  580.   if (format!=lgd_world_file_fmt) {
  581.     lgd_error = E_lw_fmt_clash;
  582.     goto closeit;
  583.   }
  584.   
  585.   lgd_load( fp ); 
  586.   if (lgd_internal_error) {
  587.     MAKE_LGD_ERR("",lgd_internal_error);
  588.     goto closeit;
  589.   }
  590.   mf_load( fp );
  591.   if (mf_error) {
  592.     MAKE_LGD_ERR("(MetaFile) ",mf_error);
  593.     goto closeit;
  594.   }
  595.   dpu_load( fp );
  596.   if (dpu_error) {
  597.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  598.     goto closeit;
  599.   }
  600.  closeit:
  601.   fclose(fp);
  602. }
  603.  
  604. /*-----------------------------------------------------------------------
  605.  * Function:     lgd_set_color
  606.  * Description:  Set the current drawing color
  607.  * Arguments IN: color: the color to use
  608.  * Returns:      nothing
  609.  * Notes:        Has no effect on monochrome displays.  Color
  610.  *               information is retained in the MF, however, so a MF
  611.  *               generated on a monochrome device, when displayed on a
  612.  *               color device, will show the colors that were in
  613.  *               effect when it was created.
  614.  */
  615. lgd_set_color( color )
  616. int color;
  617. {
  618.   cur_color = (mfe)color;
  619.   if (SEGMENT_OPEN) {
  620.     mf_append( MF_color );
  621.     mf_append( cur_color );
  622.     if (mf_error!=NULL)
  623.       MAKE_LGD_ERR("(MetaFile) ",mf_error);
  624.   }
  625.   dpu_set_color( cur_color );
  626.   if (dpu_error!=NULL)
  627.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  628. }
  629.  
  630. /*-----------------------------------------------------------------------
  631.  * Function:     lgd_set_style
  632.  * Description:  Set the current line style
  633.  * Arguments IN: style: the style to use
  634.  * Returns:      nothing
  635.  * Notes:        Has no effect on some displays.  Style information is
  636.  *               retained in the MF, however, so a MF generated on a
  637.  *               style-less device, when displayed on one which shows
  638.  *               different styles, will show the styles that were in
  639.  *               effect when it was created.
  640.  */
  641. lgd_set_style( style )
  642. int style;
  643. {
  644.   cur_style = (mfe)style;
  645.   if (SEGMENT_OPEN) {
  646.     mf_append( MF_line_style );
  647.     mf_append( cur_style );
  648.     if (mf_error!=NULL)
  649.       MAKE_LGD_ERR("(MetaFile) ",mf_error);
  650.   }
  651.   dpu_set_style( cur_style );
  652.   if (dpu_error!=NULL)
  653.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  654. }
  655.  
  656. /*-----------------------------------------------------------------------
  657.  * Function:     lgd_set_view
  658.  * Description:  Set the viewing transformation
  659.  * Arguments IN: *view: the new transformation
  660.  * Returns:      nothing
  661.  * Notes:        The view may not actually be changed by this call.
  662.  *               Call "lgd_update_display" to make sure the display
  663.  *               is current.
  664.  */
  665. lgd_set_view( view )
  666. lgd_View3 *view;
  667. {
  668.   dpu_set_view( view );
  669.   if (dpu_error!=NULL)
  670.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  671. }
  672.  
  673. /*-----------------------------------------------------------------------
  674.  * Function:     lgd_get_default_view
  675.  * Description:  Get a standard default viewing transformation
  676.  * Arguments OUT: *view: the transformation
  677.  * Returns:      nothing
  678.  * Notes:        
  679.  */
  680. lgd_get_default_view( view )
  681. lgd_View3 *view;
  682. {
  683.   dpu_get_default_view( view );
  684. }
  685.  
  686. /*-----------------------------------------------------------------------
  687.  * Function:     lgd_inquire_view
  688.  * Description:  Get the current viewwing transformation
  689.  * Arguments OUT: *view: the current transformation
  690.  * Returns:      nothing
  691.  */
  692. lgd_inquire_view( view )
  693. lgd_View3 *view;
  694. {
  695.   dpu_inquire_view( view );
  696.   if (dpu_error!=NULL)
  697.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  698. }
  699.  
  700. /*-----------------------------------------------------------------------
  701.  * Function:     lgd_set_menu
  702.  * Description:  Set the menu to be used for user interaction
  703.  * Arguments IN: *menu: the menu to use
  704.  * Returns:      nothing
  705.  */
  706. lgd_set_menu( menu )
  707. lgd_Menu *menu;
  708. {
  709.   dev_set_menu( menu );
  710. }
  711.  
  712. /*-----------------------------------------------------------------------
  713.  * Function:     lgd_main_loop
  714.  * Description:  Enter the main user-interaction loop
  715.  * Arguments:    (none)
  716.  * Returns:      nothing
  717.  */
  718. lgd_main_loop()
  719. {
  720.   dev_main_loop();
  721. }
  722.  
  723. /*-----------------------------------------------------------------------
  724.  * Function:     lgd_end_loop
  725.  * Description:  Terminate the main loop
  726.  * Arguments:    (none)
  727.  * Returns:      nothing
  728.  * Notes:        The acceptable way to terminate is to call
  729.  *               lgd_end_loop from within one of the menu
  730.  *               procs.  This will cause lgd_main_loop to return.
  731.  */
  732. lgd_end_loop()
  733. {
  734.   dev_end_loop();
  735. }
  736.  
  737. /*-----------------------------------------------------------------------
  738.  * Function:     lgd_get_string
  739.  * Description:  Get a string from the user via the keyboard
  740.  * Arguments OUT: *s: string typed by the user
  741.  * Returns:      s
  742.  * Notes:        Characters are read up to and including a newline,
  743.  *               which is translated to the null character before
  744.  *               being stored in *s.
  745.  */
  746. char *lgd_get_string( s )
  747. char *s;
  748. {
  749.   dev_get_string( s );
  750. }
  751.  
  752. /*-----------------------------------------------------------------------
  753.  * Function:     lgd_put_string
  754.  * Description:  Write a string to the user (on the screen or somewhere)
  755.  * Arguments OUT: *s: string to be written
  756.  * Returns:      nothing
  757.  */
  758. lgd_put_string( s )
  759. char *s;
  760. {
  761.   dev_put_string( s );
  762. }
  763.  
  764. /*-----------------------------------------------------------------------
  765.  * Function:     lgd_confirm
  766.  * Description:  Get confirmation (yes/no answer) from user
  767.  * Arguments IN: *string: prompt to be printed
  768.  * Returns:      YES (1) or NO (0)
  769.  */
  770. lgd_confirm( string )
  771. char *string;
  772. {
  773.   int answer;
  774.  
  775.   answer = dev_confirm( string );
  776.   return( answer );
  777. }
  778.  
  779. /*-----------------------------------------------------------------------
  780.  * Function:     lgd_get_point
  781.  * Description:  Get a point in the current world from the user
  782.  * Arguments OUT: v: the gotten point
  783.  * Returns:      nothing
  784.  */
  785. lgd_get_point( v )
  786. double v[];
  787. {
  788.   dev_get_point( v );
  789. }
  790.  
  791. /*-----------------------------------------------------------------------
  792.  * Function:     lgd_inquire_color
  793.  * Description:  Tell what the current color is
  794.  * Arguments OUT: *color: the current color
  795.  * Returns:      nothing
  796.  */
  797. lgd_inquire_color( color )
  798. int *color;
  799. {
  800.   *color = cur_color;
  801. }
  802.  
  803. /*-----------------------------------------------------------------------
  804.  * Function:     lgd_inquire_style
  805.  * Description:  Tell what the current line style is
  806.  * Arguments OUT: *style: the current style
  807.  * Returns:      nothing
  808.  */
  809. lgd_inquire_style( style )
  810. int *style;
  811. {
  812.   *style = cur_style;
  813. }
  814.  
  815. /*-----------------------------------------------------------------------
  816.  * Function:     lgd_inquire_menu
  817.  * Description:  Tell what the current menu is
  818.  * Arguments OUT: **menu: the current menu
  819.  * Returns:      nothing
  820.  */
  821. lgd_inquire_menu( menu )
  822. lgd_Menu **menu;
  823. {
  824.   dev_inquire_menu( menu );
  825. }
  826.  
  827. /*-----------------------------------------------------------------------
  828.  * Function:     lgd_inquire_current_segment
  829.  * Description:  Tell what the current segment is
  830.  * Arguments OUT: *segment: the current segment
  831.  * Returns:      nothing
  832.  */
  833. lgd_inquire_current_segment( segment )
  834. int *segment;
  835. {
  836.   *segment = cur_segment;
  837. }
  838.  
  839. /*-----------------------------------------------------------------------
  840.  * Function:     lgd_inquire_segment_visibility
  841.  * Description:  Get the visibility attribute of a segment
  842.  * Arguments IN: segment_number: number of segment
  843.  *          OUT: *visibility: 1=visible, 0=invisible
  844.  * Returns:      *visibility
  845.  * Notes:        Returns -1 and sets an error if segment does not
  846.  *         exist
  847.  */
  848. lgd_inquire_segment_visibility( segment_number, visibility )
  849. int segment_number, *visibility;
  850. {
  851.   mfa address;
  852.  
  853.   address = segment_address( (mfe)segment_number );
  854.   if (address==NULL_SEG_ADDRESS) {
  855.     lgd_error = E_inq_noseg_visi;
  856.     return(-1);
  857.   }
  858.   *visibility = mf_peek( address+VIS_OS );
  859.   return( *visibility );
  860. }
  861.  
  862. /*-----------------------------------------------------------------------
  863.  * Function:     lgd_set_pick_tolerance
  864.  * Description:  set the tolerance for picking operations
  865.  * Arguments IN: t: the new tolerance
  866.  * Returns:      nothing
  867.  * Notes:        This has effect only on devices which are able to
  868.  *               implement picking.
  869.  */
  870. lgd_set_pick_tolerance(t)
  871. double t;
  872. {
  873.   lgd_pick_tolerance = t;
  874. }
  875.  
  876. /*-----------------------------------------------------------------------
  877.  * Function:     lgd_inquire_pick_tolerance
  878.  * Description:  get the current pick tolerance
  879.  * Arguments: OUT: *t: the current pick tolerance
  880.  * Returns:      nothing
  881.  * Notes:        This is meaningful only on devices which are able to
  882.  *               implement picking.
  883.  */
  884. lgd_inquire_pick_tolerance(t)
  885. double *t;
  886. {
  887.   *t = lgd_pick_tolerance;
  888. }
  889.  
  890. /*-----------------------------------------------------------------------
  891.  * Function:     lgd_pick_segment
  892.  * Description:  see dpu_pick_segment in dpu.c (part of device driver)
  893.  */
  894. lgd_pick_segment( s, n )
  895. int **s, *n;
  896. {
  897.   dpu_pick_segment(s, n);
  898. }
  899.  
  900. /*-----------------------------------------------------------------------
  901.  * Function:    lgd_signal
  902.  * Description:    set a trap for a Unix signal
  903.  * Args  IN:    sig: the signal to catch
  904.  *        func: the function to call when the signal is caught
  905.  * Notes:    LGD applications should call this instead of signal(3)
  906.  *        in order to peacefullly exist with lgd_main_loop().
  907.  */
  908. lgd_signal(sig, func)
  909. int sig, (*func)();
  910. {
  911.   dev_signal(sig, func);
  912. }
  913.  
  914. /*-----------------------------------------------------------------------
  915.  * Function:    lgd_set_input_func
  916.  * Description:    specify a function to call when input is available from
  917.  *        a pipe
  918.  * Args  IN:    func: the function to call
  919.  *        fd: file descriptor of pipe
  920.  */
  921. lgd_set_input_func(func, fd)
  922. int (*func)(), fd;
  923. {
  924.   dev_set_input_func(func, fd);
  925. }
  926.  
  927. /*--------------------End of External Procedures------------------------*/
  928.               
  929. /************************************************************************
  930.  *             INTERNAL PROCEDURES                *
  931.  ************************************************************************/
  932.  
  933. /*-----------------------------------------------------------------------
  934.  * Function:     move_abs
  935.  * Description:  Move the current point to a new point
  936.  * Arguments IN: v: the point to move to
  937.  * Returns:      nothing
  938.  * Notes:        v MUST be inside (or on the boundary of) the world.
  939.  *               If it is not, an error is set and the current point
  940.  *               is left unchanged.
  941.  */
  942. static
  943. move_abs( v )
  944.      double v[];
  945. {
  946.   mfe ivec[MAXDIM];
  947.   
  948.   if NO_SEGMENT_OPEN {
  949.     lgd_error = E_md_noseg;
  950.     return;
  951.   }
  952.   if (in_world_box(v)) {
  953.     pen_up();
  954.     can_int_coord( ivec, v );
  955.     mf_append_array( ivec, lgd_dim );
  956.     if (mf_error==NULL) {
  957.       LGD_copy_vec( cp, v );
  958.       dpu_move( v );
  959.       if (dpu_error!=NULL) {
  960.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  961.       }
  962.     }
  963.     else {
  964.       MAKE_LGD_ERR("(MetaFile) ",mf_error);
  965.     }
  966.   }
  967.   else {
  968.     lgd_error = E_out_of_world;
  969.   }
  970. }
  971.  
  972. /*--------------------------------------------------------------
  973.  * Function:     draw_abs
  974.  * Description:  Draw from the current point to a new point, and
  975.  *               then make that new point the current point
  976.  * Arguments IN: v: the point to draw to
  977.  * Returns:      nothing
  978.  * Notes:        v MUST be inside (or on the boundary of) the world.
  979.  *               If it is not, an error is set and the current point
  980.  *               is left unchanged.
  981.  */
  982. static
  983. draw_abs( v )
  984.      double v[];
  985. {
  986.   mfe ivec[MAXDIM];
  987.   
  988.   if NO_SEGMENT_OPEN {
  989.     lgd_error = E_md_noseg;
  990.     return;
  991.   }
  992.   if (in_world_box(v)) {
  993.     pen_down();
  994.     can_int_coord( ivec, v );
  995.     mf_append_array( ivec, lgd_dim );
  996.     if (mf_error==NULL) {
  997.       LGD_copy_vec( cp, v );
  998.       dpu_draw( v );
  999.       if (dpu_error!=NULL) {
  1000.     MAKE_LGD_ERR("(DPU) ",dpu_error);
  1001.       }
  1002.     }
  1003.     else
  1004.       MAKE_LGD_ERR("(MetaFile) ",mf_error);
  1005.   }
  1006.   else {
  1007.     lgd_error = E_out_of_world;
  1008.   }
  1009. }
  1010.  
  1011. /*-----------------------------------------------------------------------
  1012.  * Function:     pen_up
  1013.  * Description:  Raise the pen if it's not already up
  1014.  * Arguments:    none
  1015.  * Returns:      nothing
  1016.  */
  1017. static
  1018. pen_up()
  1019. {
  1020.   if NO_SEGMENT_OPEN {
  1021.     lgd_internal_error = E_pu_noseg;
  1022.     return;
  1023.   }
  1024.   if PEN_IS_DOWN {
  1025.     mf_append( MF_pen_up );
  1026.     if (mf_error==NULL)
  1027.       pen_status = UP;
  1028.     else 
  1029.       MAKE_LGD_INTERNAL_ERR("(MetaFile) ",mf_error);
  1030.   }
  1031. }
  1032.  
  1033. /*--------------------------------------------------------------
  1034.  * Function:     pen_down
  1035.  * Description:  Lower the pen if it's not already down
  1036.  * Arguments:    none
  1037.  * Returns:      nothing
  1038.  */
  1039. static
  1040. pen_down()
  1041. {
  1042.   if NO_SEGMENT_OPEN {
  1043.     lgd_internal_error = E_pd_noseg;
  1044.     return;
  1045.   }
  1046.   if PEN_IS_UP {
  1047.     mf_append( MF_pen_down );
  1048.     if (mf_error==NULL)
  1049.       pen_status = DOWN;
  1050.     else
  1051.       MAKE_LGD_INTERNAL_ERR("(MetaFile) ",mf_error);
  1052.   }
  1053. }
  1054.  
  1055. /*-----------------------------------------------------------------------
  1056.  * Function:     in_world_box
  1057.  * Description:  Check to see if a point is in the world box or not.
  1058.  * Arguments IN: v: the point to check
  1059.  * Returns:      YES or NO
  1060.  * Notes:        On the boundary counts as IN.
  1061.  */
  1062. static
  1063. in_world_box( v )
  1064. double v[];
  1065. {
  1066.   int i, inbox;
  1067.   
  1068.   inbox = YES;
  1069.   i = 0;
  1070.   while ( (inbox) && (i<lgd_dim) ) {
  1071.     inbox = (   (lgd_wbox[0][i]<=v[i]       )
  1072.          &&(      v[i]<=lgd_wbox[1][i] ) );
  1073.     ++i;
  1074.   }
  1075.   return(inbox);
  1076. }
  1077.  
  1078. /*-----------------------------------------------------------------------
  1079.  * Function:     can_int_coord
  1080.  * Description:  Convert world coords to canonical integer coords
  1081.  * Arguments IN: v: vector in world coords to be converted
  1082.  *          OUT: ivec: integer vector answer
  1083.  * Returns:      nothing
  1084.  * Notes:       This procedure ASSUMES that v is inside the world box.
  1085.  *              If v is not in the world box, the results could be
  1086.  *              disasterous.
  1087.  */
  1088. static
  1089. can_int_coord( ivec, v )
  1090. mfe ivec[];
  1091. double v[];
  1092. {
  1093.   int i;
  1094.   
  1095.   for (i=0; i<lgd_dim; ++i)
  1096.     ivec[i] = (mfe) ( (v[i]-lgd_wbox[0][i]) * lgd_wscale[i] );
  1097. }
  1098.  
  1099. /*-----------------------------------------------------------------------
  1100.  * Function:     segment_address
  1101.  * Description:  Get the address of a segment in the MetaFile
  1102.  * Arguments IN: segment_number: number of segment to get address of
  1103.  * Returns:      the address
  1104.  * Notes:        Returns NULL_SEG_ADDRESS if the given segment doesn't
  1105.  *           exist
  1106.  */
  1107. static mfa
  1108. segment_address( segment_number )
  1109.      mfe segment_number;
  1110. {
  1111.   mfa address, last;
  1112.   
  1113.   last = mf_last_addr();
  1114.   for (address=mf_first_addr(); address<last; ++address)
  1115.     if (mf_peek(address)==MF_begin_segment)
  1116.       if (mf_peek(address+NAME_OS)==segment_number)
  1117.     return(address);
  1118.   return(NULL_SEG_ADDRESS);
  1119. }
  1120.  
  1121. /*-----------------------------------------------------------------------
  1122.  * Function:     lgd_save
  1123.  * Description:  write values for module "lgd" to a file
  1124.  * Arguments IN: fp: the file to write to
  1125.  * Returns:      nothing
  1126.  */
  1127. static
  1128. lgd_save( fp )
  1129.      FILE *fp;
  1130. {
  1131.   int items_written;
  1132.  
  1133. #define    SAVEIT(x,type)    {items_written = fwrite( \
  1134.         (char*)x,sizeof(type), 1, fp );\
  1135.         if (items_written!=1) \
  1136.         {lgd_internal_error=E_swd_bad_write; return; } }
  1137.   /*
  1138.    *********************
  1139.    * THIS IS FORMAT 3  *
  1140.    *********************
  1141.    */
  1142.   SAVEIT( &lgd_dim, int);
  1143.   SAVEIT( &lgd_header_length, int);
  1144.   SAVEIT( &lgd_trailer_length, int);
  1145.   SAVEIT( &pen_status, int);
  1146.   SAVEIT( cp, cp );
  1147.   SAVEIT( lgd_wbox, lgd_wbox );
  1148.   SAVEIT( lgd_wscale, lgd_wscale );
  1149.   SAVEIT( &cur_segment, mfe );
  1150.   SAVEIT( &cur_color, mfe );
  1151.   SAVEIT( &cur_style, mfe );
  1152.   
  1153. #undef    SAVEIT
  1154. }
  1155.  
  1156. /*-----------------------------------------------------------------------
  1157.  * Function:     lgd_load
  1158.  * Description:  read values for module "lgd" from a file
  1159.  * Arguments IN: fp: the file to read from
  1160.  * Returns:      nothing
  1161.  */
  1162. static
  1163. lgd_load( fp )
  1164.      FILE *fp;
  1165. {
  1166.   int items_read;
  1167.   
  1168. #define    LOADIT(x,type)    {items_read = fread( \
  1169.         (char*)x,sizeof(type), 1, fp );\
  1170.         if (items_read!=1) \
  1171.         {lgd_internal_error=E_swd_bad_read; return; } }
  1172.  
  1173.   /*
  1174.    *********************
  1175.    * THIS IS FORMAT 3  *
  1176.    *********************
  1177.    */
  1178.  
  1179.   LOADIT( &lgd_dim, int);
  1180.   LOADIT( &lgd_header_length, int);
  1181.   LOADIT( &lgd_trailer_length, int);
  1182.   LOADIT( &pen_status, int);
  1183.   LOADIT( cp, cp );
  1184.   LGD_copy_vec(crp, cp);
  1185.   LOADIT( lgd_wbox, lgd_wbox );
  1186.   LOADIT( lgd_wscale, lgd_wscale );
  1187.   LOADIT( &cur_segment, mfe );
  1188.   LOADIT( &cur_color, mfe );
  1189.   LOADIT( &cur_style, mfe );
  1190.   
  1191. #undef    LOADIT
  1192. }
  1193.  
  1194. /*-----------------------------------------------------------------------
  1195.  * Function:     generate_unique_segment_number
  1196.  * Description:  get unique number to use for a new segment
  1197.  * Arguments:    (none)
  1198.  * Returns:      the number
  1199.  */
  1200. static mfe
  1201. generate_unique_segment_number()
  1202. {
  1203.   mfa maxsegnum, address, last;
  1204.   mfe segnum;
  1205.   char *flags, *calloc();
  1206.   
  1207. #define USED 'u'
  1208.   last = mf_last_addr();
  1209.   if (last==0)            /* MF is empty */
  1210.     segnum = 1;
  1211.   else {            /* MF is not empty */
  1212.     /*  Get max possible seg number and seg up flags array: */
  1213.     maxsegnum = mf_length() / (lgd_header_length + lgd_trailer_length) - 1;
  1214.     segnum = NULL_SEGMENT;
  1215.     flags = calloc( (unsigned)(maxsegnum+1), sizeof(char) );
  1216.     /* Go through MF, marking used segment numbers in flags array: */
  1217.     for (address=mf_first_addr(); address<last; ++address) {
  1218.       if (mf_peek(address)==MF_begin_segment) {
  1219.     if ( (segnum=mf_peek(address+NAME_OS)) > maxsegnum ) {
  1220.       lgd_internal_error = E_max_segs;
  1221.       break;
  1222.     }
  1223.     else
  1224.       flags[segnum] = USED;
  1225.       }
  1226.     }
  1227.     if (segnum!=NULL_SEGMENT) {
  1228.       /* Now go thru flags array to find first unused number */
  1229.       for (segnum=1; segnum<=maxsegnum; ++segnum)
  1230.     if (flags[segnum]!=USED) break;
  1231.       if (segnum>maxsegnum) {
  1232.     lgd_internal_error = E_max_segs;
  1233.     segnum = NULL_SEGMENT;
  1234.       }
  1235.     }
  1236.     free(flags);
  1237.   }
  1238.   return(segnum);
  1239. #undef USED 'u'
  1240. }
  1241.  
  1242. /*-----------------------------------------------------------------------
  1243.  * Function:     error_string
  1244.  * Description:  construct an error message string
  1245.  * Arguments IN: prefix: error prefix
  1246.  *         message: the error message
  1247.  * Returns:      nothing
  1248.  * Notes:        The pointer points to internal storage space which
  1249.  *               is reused on subsequent calls.
  1250.  */
  1251. static char *
  1252. error_string( prefix, message )
  1253. char *prefix, *message;
  1254. {
  1255.   static char ermsg[200];
  1256.  
  1257.   sprintf( ermsg, "%s%s", prefix, message );
  1258.   return( ermsg );
  1259. }
  1260.  
  1261. /*======================================================================
  1262.  *
  1263.  *         CLIPPING STUFF
  1264.  *
  1265.  *   This is an adaptation of the Cohen-Sutherland clipping algorithm,
  1266.  *   from pages 148-149 of Foley & Van Dam's `Fundamentals of
  1267.  *   Interactive Computer Graphics'.  This version is modified in two
  1268.  *   ways:
  1269.  *    1. It does 3-dimensional clipping
  1270.  *    2. It is designed to be used for translating one set of
  1271.  *       move/draw commands (with no restrictions on the points
  1272.  *       moved or drawn to) to another set of move/draw commands
  1273.  *       in which the points are restricted to lie within the
  1274.  *       world box.
  1275.  */
  1276.  
  1277. typedef unsigned short int Outcode_int;
  1278.  
  1279. typedef struct outcode_s {
  1280.   unsigned bit1    : 1;
  1281.   unsigned bit2    : 1;
  1282.   unsigned bit3    : 1;
  1283.   unsigned bit4    : 1;
  1284.   unsigned bit5    : 1;
  1285.   unsigned bit6    : 1;
  1286.   unsigned pad    : BITSPERBYTE*sizeof(Outcode_int) - 6;
  1287. } Outcode_struct;
  1288.  
  1289. typedef union outcode_u {
  1290.   Outcode_int        I;
  1291.   Outcode_struct    S;
  1292. } Outcode;
  1293.  
  1294. #define TRIVIAL_REJECT(c1,c2)    (c1.I&c2.I)
  1295. #define TRIVIAL_ACCEPT(c1,c2)    (!(c1.I|c2.I))
  1296.  
  1297. #define SWAP(x1,y1,z1,x2,y2,z2,c1,c2,dtemp,ctemp)   \
  1298.   dtemp   = x1;   x1   = x2;   x2   = dtemp;  \
  1299.   dtemp   = y1;   y1   = y2;   y2   = dtemp;  \
  1300.   dtemp   = z1;   z1   = z2;   z2   = dtemp;  \
  1301.   ctemp.I = c1.I; c1.I = c2.I; c2.I = ctemp.I;
  1302.  
  1303. #define xmin lgd_wbox[0][0]
  1304. #define ymin lgd_wbox[0][1]
  1305. #define zmin lgd_wbox[0][2]
  1306. #define xmax lgd_wbox[1][0]
  1307. #define ymax lgd_wbox[1][1]
  1308. #define zmax lgd_wbox[1][2]
  1309.  
  1310. /*-----------------------------------------------------------------------
  1311.  * Function:     outcodes
  1312.  * Description:  compute the Outcode of a point
  1313.  * Arguments IN: x,y,z: the coords of the point
  1314.  * Returns:      the Outcode (as its "Outcode_int" member)
  1315.  */
  1316. static Outcode_int
  1317. outcode(x, y, z)
  1318.      double x,y,z;
  1319. {
  1320.   Outcode code;
  1321.  
  1322.   code.I = 0;
  1323.   code.S.bit1 = (z > zmax);
  1324.   code.S.bit2 = (z < zmin);
  1325.   code.S.bit3 = (y > ymax);
  1326.   code.S.bit4 = (y < ymin);
  1327.   code.S.bit5 = (x > xmax);
  1328.   code.S.bit6 = (x < xmin);
  1329.   return(code.I);
  1330. }
  1331.  
  1332. /*-----------------------------------------------------------------------
  1333.  * Function:     clipit
  1334.  * Description:  clips line segment to world box
  1335.  * Arguments IN: a: initial point of segment
  1336.  *               b: terminal point of segment
  1337.  *          OUT: a: initial point of clipped segment
  1338.  *               b: terminal point of clipped segment
  1339.  *               *clipa: flag telling whether point a was clipped
  1340.  *               *accept: flag telling whether segment is visible
  1341.  *                  at all.
  1342.  * Returns:      nothing
  1343.  * Notes:        If visible==NO upon return, then the values of the
  1344.  *               other 3 parameters are meaningless.
  1345.  */
  1346. static
  1347. clipit(a, b, clipa, accept)
  1348. double a[], b[];
  1349. int *clipa, *accept;
  1350. {
  1351.   double  x1, y1, z1, x2, y2, z2;
  1352.   double dtemp, factor;
  1353.   Outcode c1,c2,ctemp;
  1354.   int done, swapped, first_pass;
  1355.  
  1356.   x1 = a[0]; y1 = a[1]; z1 = a[2];
  1357.   x2 = b[0]; y2 = b[1]; z2 = b[2];
  1358.  
  1359.   done = NO;
  1360.   *accept = NO;
  1361.   swapped = NO;
  1362.   first_pass = YES;
  1363.   do {
  1364.     /* compute Outcodes */
  1365.     c1.I = outcode(x1, y1, z1);
  1366.     if (first_pass) {
  1367.       *clipa = (c1.I!=0);    /* (Outcode nonzero --> pt is OUT) */
  1368.       first_pass = NO;
  1369.     }
  1370.     c2.I = outcode(x2, y2, z2);
  1371.     /* check for trivial rejection */
  1372.     if (TRIVIAL_REJECT(c1, c2))
  1373.       done = YES;
  1374.     else {
  1375.       /* check for trivial acceptance */
  1376.       if (*accept=TRIVIAL_ACCEPT(c1,c2))
  1377.     done = YES;
  1378.       else {    /* Subdivide the line */
  1379.         /* First, swap if necessary to guarantee that point 1 is OUT */
  1380.         if (!c1.I) {
  1381.       SWAP(x1, y1, z1, x2, y2, z2, c1, c2, dtemp, ctemp);
  1382.       swapped = !swapped;
  1383.         }
  1384.     /* Now do the subdivision */
  1385.     if (c1.S.bit1) {        /* z > zmax */
  1386.           factor = (zmax - z1) / (z2 - z1);
  1387.       x1 = x1 + (x2 - x1) * factor;
  1388.       y1 = y1 + (y2 - y1) * factor;
  1389.       z1 = zmax;
  1390.     }
  1391.     else if (c1.S.bit2) {        /* z < zmin */
  1392.           factor = (zmin - z1) / (z2 - z1);
  1393.       x1 = x1 + (x2 - x1) * factor;
  1394.       y1 = y1 + (y2 - y1) * factor;
  1395.       z1 = zmin;
  1396.     }
  1397.     else if (c1.S.bit3) {        /* y > ymax */
  1398.           factor = (ymax - y1) / (y2 - y1);
  1399.       x1 = x1 + (x2 - x1) * factor;
  1400.       z1 = z1 + (z2 - z1) * factor;
  1401.       y1 = ymax;
  1402.     }
  1403.     else if (c1.S.bit4) {        /* y < ymin */
  1404.           factor = (ymin - y1) / (y2 - y1);
  1405.       x1 = x1 + (x2 - x1) * factor;
  1406.       z1 = z1 + (z2 - z1) * factor;
  1407.       y1 = ymin;
  1408.     }
  1409.     else if (c1.S.bit5) {        /* x > xmax */
  1410.           factor = (xmax - x1) / (x2 - x1);
  1411.       y1 = y1 + (y2 - y1) * factor;
  1412.       z1 = z1 + (z2 - z1) * factor;
  1413.       x1 = xmax;
  1414.     }
  1415.     else if (c1.S.bit6) {        /* x < xmin */
  1416.           factor = (xmax - x1) / (x2 - x1);
  1417.       y1 = y1 + (y2 - y1) * factor;
  1418.       z1 = z1 + (z2 - z1) * factor;
  1419.       x1 = xmin;
  1420.     }
  1421.       }
  1422.     }
  1423.   }  while (!done);
  1424.  
  1425.   if (accept) {
  1426.     if (swapped) {
  1427.       a[0] = x2; a[1] = y2; a[2] = z2;
  1428.       b[0] = x1; b[1] = y1; b[2] = z1;
  1429.     }
  1430.     else {
  1431.       a[0] = x1; a[1] = y1; a[2] = z1;
  1432.       b[0] = x2; b[1] = y2; b[2] = z2;
  1433.     }
  1434.   }
  1435. }
  1436.